CoreAnimationとUIBezierPathを使用して円が拡大するアニメーションを実装する
はじめに
こんばんは。モバイルアプリサービス部の平屋です。
本記事では、CoreAnimationとUIBezierPathを使用して円が拡大するアニメーションを実装する方法を紹介します。
以下のスクリーンショットが実装結果です。
検証環境
本記事は以下の環境で検証を行っています。
- macOS Sierra 10.13.2
- Xcode Version 9.2 (9C40b)
実装
さっそく実装を紹介していきます。
CAShapeLayerを作成
アニメーション描画用のCAShapeLayer
を作成し、ビューのレイヤーに追加します。
class ExpandingCircleView: UIView { var circleLayer: CAShapeLayer! override func awakeFromNib() { super.awakeFromNib() circleLayer = CAShapeLayer() circleLayer.frame = bounds circleLayer.fillColor = UIColor.black.withAlphaComponent(0.2).cgColor circleLayer.needsDisplayOnBoundsChange = true layer.addSublayer(circleLayer) } func animate() { // ... } }
アニメーションの作成と適用
(1) アニメーション開始/終了時のパスを作成
アニメーション開始時のパスとして、半径100ptの円形のパスを作成し、アニメーションの開始値としてレイヤーに追加します。
また、終了時のパスとして、幅/高さがビューと等しい円形のパスを作成します。
func animate() { let startSize = CGSize(width: 100, height: 100) let inset = (bounds.width / 2) - (startSize.width / 2) let startRect = bounds.insetBy(dx: inset, dy: inset) let startPath = UIBezierPath(ovalIn: startRect).cgPath circleLayer.path = startPath let endPath = UIBezierPath(ovalIn: bounds).cgPath // ... }
(2) パスを変化させるアニメーションを作成
アニメーション対象が「パス」のアニメーションを作成し、終了値/デュレーションなどを設定します。
func animate() { // ... let pathAnimation = CABasicAnimation(keyPath: "path") // パスを指定 pathAnimation.toValue = endPath // 終了値 pathAnimation.duration = 2 // アニメーション時間 pathAnimation.fillMode = kCAFillModeForwards // アニメーション終了地点にフレームを残す pathAnimation.isRemovedOnCompletion = false // アニメーション終了後にフレームを残す // ... }
(3) フェードアウトさせるアニメーションを作成
アニメーション対象が「不透明度」のアニメーションを作成し、開始値/終了値/デュレーションなどを設定します。
func animate() { // ... let fadeOutAnimation = CABasicAnimation(keyPath: "opacity") // 不透明度を指定 fadeOutAnimation.fromValue = 1 // 開始値 fadeOutAnimation.toValue = 0 // 終了値 fadeOutAnimation.duration = 1 // アニメーション時間 fadeOutAnimation.beginTime = 2 // 開始時間 // ... }
(4) 2つのアニメーションをグルーピング
(2)と(3)で作成したアニメーションをグルーピングし、デュレーション/繰り返し回数などを設定します。
そして、グループをレイヤーに追加します。
func animate() { // ... let animationGroup = CAAnimationGroup() animationGroup.duration = pathAnimation.duration + fadeOutAnimation.duration // アニメーション時間 animationGroup.repeatCount = .infinity // リピート回数:無限 animationGroup.animations = [pathAnimation, fadeOutAnimation] circleLayer.add(animationGroup, forKey: nil) }
さいごに
本記事では、CoreAnimationとUIBezierPathを使用して円が拡大するアニメーションを実装する方法を紹介しました。
サンプルコードは以下のリポジトリで公開してます。
参考資料
- Core Animation | Apple Developer Documentation
- Core Animationプログラミングガイド (TP40004514 0.0.0)
- Fun with CAShapeLayer - Animations and Drawing Shapes in Swift | Jameson Quave
- iphone - CALayers didn't get resized on its UIView's bounds change. Why? - Stack Overflow
- iphone - CABasicAnimation unlimited repeat without HUGE_VALF? - Stack Overflow
- [iOS]CoreAnimationでお手軽にシーケンシャルなアニメーションを実装する - Qiita
- Core Animation 中級編 - Qiita